from django.contrib import admin
from . import models
from bddjango.adminclass import BaseAdmin, BulkDeleteMixin
import os
import shutil
from bddjango import copy_to
from bdtime import Time
from bddjango import get_key_from_request_data_or_self_obj
from bddjango import unzip_to
import zipfile
from bddjango import DownloadFileMixin
from tools.run_cmd import RunCmd


def judge_webssh_state():
    run_cmd = RunCmd()
    commands = 'ps -ef | grep wssh | grep -v "grep"'
    output, error = run_cmd.run_cmd(commands)
    if output:
        print('webssh is running!')
        return True
    else:
        print('webssh is not running!')
        return False


@admin.register(models.FileSelection)
class FileSelection(BaseAdmin, BulkDeleteMixin, DownloadFileMixin):
    # custom_import_and_export_buttons = False
    # has_import_perm = False
    # has_export_perm = False
    # default_export_action = False

    def get_queryset(self, *args, **kwargs):
        ret = super().get_queryset(*args, **kwargs)
        if judge_webssh_state():
            text = '停止webssh'
        else:
            text = '启动webssh'

        if ret.exists():
            FileSelection.fc_switch_webssh.layer = None
        else:
            FileSelection.fc_switch_webssh.layer = FileSelection.fc_switch_webssh_layer_dc
            FileSelection.fc_switch_webssh.layer['title'] = text

        FileSelection.fc_switch_webssh.short_description = text
        return ret

    path_field_name = 'path'
    actions = ['fc_clean_data', 'bulk_delete', 'fc_switch_webssh', 'webssh', 'upload_file''download_file', ]  # 'synctohub',

    def webssh(self, request, queryset):
        pass

    webssh.short_description = 'Web终端'
    # icon，参考element-ui icon与https://fontawesome.com
    # webssh.icon = 'fas fa-audio-description'
    webssh.icon = 'el-icon-s-platform'
    # webssh.type = 'danger'
    webssh.style = 'background-color:#283846; color: white'
    # synctohub.style = 'color:#283846;'

    # webssh.type = 'success'

    # action_type 0=当前页内打开，1=新tab打开，2=浏览器tab打开
    webssh.action_type = 1

    # if 1:
    #     # 跳过登录页面，直接传入hostname, username, password三个参数访问设备
    #     import base64
    #     _passwd = "passwd"
    #     passwd = base64.b64encode(_passwd.encode('utf-8')).decode('utf-8')
    #     username = 'root'
    #     hostname = 'localhost'
    #     title = '终端'
    #     href = f"/api/webssh/?hostname={hostname}&username={username}&password={passwd}&title={title}"
        # print(href)
        # print(passwd)
    # webssh.action_url = href
    webssh.action_url = "/api/file_upload/SSHBox/"
    # webssh.action_url = "https://www.bing.com/?mkt=zh-CN"

    def synctohub(self, request):
        pass

    synctohub.short_description = "同步项目到github"
    synctohub.icon = 'el-icon-upload'
    synctohub.type = 'danger'
    synctohub.style = 'color:#283846;'
    synctohub.layer = {
        'title': '同步项目到github?',
        'tips': f'请选择将同步的项目:',
        'params': [
            {
                'type': 'checkbox',
                'key': 'checkbox',
                # 必须指定默认值
                # 'value': ['admin.py', 'urls.py', 'views.py'],
                'value': ['admin.py', 'urls.py', 'views.py'],
                'label': '代码类型',
                'options': [
                    # {
                    #     'key': '0',
                    #     'label': '全部'
                    # },
                    {
                        'key': '1',
                        'label': 'admin.py'
                    },
                    {
                        'key': '2',
                        'label': 'urls.py'
                    },
                    {
                        'key': '2',
                        'label': 'views.py'
                    },
                ]
            },
            {
                'type': 'switch',
                'key': 'use_complete_model_view',
                'label': '增删改查',
                'value': 1
            },
        ]
    }

    def fc_switch_webssh(self, request, queryset):
        from django.http import JsonResponse
        # from bddjango import convert_query_parameter_to_bool
        #
        # post = request.POST
        #
        # is_open_webssh = post.get('is_open_webssh')
        # # is_open_webssh = convert_query_parameter_to_bool(is_open_webssh)
        # print(f'~~~ is_open_webssh: {is_open_webssh}')

        if judge_webssh_state():
            os.system('bash shells/killport.sh 28000')
            msg = '已停止webssh'
        else:
            os.system('python run_webssh.py')
            msg = '启动webssh成功'

        self.message_user(request, msg)

        if hasattr(FileSelection.fc_switch_webssh, 'layer') and getattr(FileSelection.fc_switch_webssh, 'layer'):
            return JsonResponse(data={
                'status': 'success',
                'msg': 'ok'
            })

    # switch_webssh.short_description = a.short_description
    fc_switch_webssh.short_description = "开关webssh"
    # fc_switch_webssh.icon = 'el-icon-upload'
    fc_switch_webssh.icon = 'el-icon-switch-button'
    fc_switch_webssh.type = 'danger'
    fc_switch_webssh_layer_dc = {
        'title': fc_switch_webssh.short_description,
        'tips': '操作可能比较耗时, 请耐心等待~',
    }
    fc_switch_webssh.layer = fc_switch_webssh_layer_dc

    def upload_file(self, request, queryset):
        from django.http import JsonResponse
        tt = Time()

        # 这里的upload 就是和params中配置的key一样
        upload = request.FILES['upload']

        obj: models.FileSelection = queryset[0]
        dst = obj.path
        assert dst, '目标路径不能为空!'
        if not os.path.exists(dst):
            if dst.endswith('/'):
                os.makedirs(dst, exist_ok=True)
            else:
                os.makedirs(os.path.dirname(dst), exist_ok=True)

        if not upload:
            return JsonResponse(data={
                'status': 'error',
                'msg': f'上传文件不能为空!'
            })
        f_name = upload._name
        if os.path.isdir(dst):
            dst = os.path.join(dst, f_name)
        base_name, f_format = os.path.splitext(upload._name)
        file_contents = upload.file.read().decode('utf-8')
        tempdir = 'tempdir/admin/FileSelection/upload_file/'
        os.makedirs(tempdir, exist_ok=True)

        def save_src(src, file_contents):
            with open(src, 'w', encoding='utf-8') as f:
                f.write(file_contents)

        if f_format == 'zip':
            print('上传了一个zip~')
            src = os.path.join(tempdir, f_name)
            save_src(src, file_contents)
            unzip_to(src, dst)
        else:
            src = os.path.join(tempdir, f_name)
            save_src(src, file_contents)
            copy_to(src, dst)

        from bddjango.tools.remove_temp_file import remove_temp_file
        remove_temp_file(tempdir)

        self.message_user(request, f"上传成功, 耗时: {tt.now(1)}秒.")
        return JsonResponse(data={
            'status': 'success',
            'msg': 'ok'
        })

    upload_file.short_description = '上传文件'
    upload_file.type = 'success'
    upload_file.icon = 'el-icon-upload'
    upload_file.enable = True

    upload_file.layer = {
        'params': [{
            'type': 'file',
            'key': 'upload',
            'label': '文件'
        }]
    }


class UploadFileMixin:
    """
    批量上传

    - overwrite: 是否覆盖, 默认否
    """

    overwrite = False

    @admin.action(permissions=['delete'])
    def upload_file(self, request, queryset=None, model=None):
        tt = Time()
        overwrite = get_key_from_request_data_or_self_obj(request._post, self, 'overwrite', get_type='bool')

        obj: models.UploadFile = queryset[0]

        src = obj.file.path
        dst = obj.replace_path

        if zipfile.is_zipfile(src):
            print(f'*** {tt.get_current_beijing_time_str()} --- 前端下载完毕, 准备解压... {src}   ---   is_zipfile():', zipfile.is_zipfile(src))
            unzip_to(src, dst, overwrite=overwrite)
        else:
            copy_to(src, dst, overwrite=overwrite)

        obj.save()
        self.message_user(request, f"成功, 耗时: {tt.now(1)}秒.")

    upload_file.short_description = '增量上传'
    upload_file.type = 'success'
    upload_file.icon = 'el-icon-upload'
    upload_file.enable = True
    upload_file.confirm = "确定增量上传? 此举不删除目标路径下的原有文件!"


# --- 上传[文件 or zip], 并自动解压, 然后执行脚本, 将上传的文件覆盖到指定目录.
@admin.register(models.UploadFile)
class UploadFile(BaseAdmin, BulkDeleteMixin, UploadFileMixin):
    actions = ['bulk_delete', 'publish_action', 'upload_file', 'fc_restart_nginx', 'fc_clean_file_cache']
    list_filter = ['replace_path']

    publish_overwrite = True  # 覆盖 or 增量上传

    def fc_clean_file_cache(self, request, queryset=None, model=None):
        from bdtime import tt
        tt.__init__()
        cache_dir_path = 'tempdir/cache'
        if os.path.exists(cache_dir_path):
            shutil.rmtree(cache_dir_path)
            self.message_user(request, f"清理文件缓存成功! 耗时: {tt.now(1)}秒.")
        else:
            self.message_user(request, f'已清空缓存文件夹[{cache_dir_path}]')

    fc_clean_file_cache.short_description = "清理文件缓存"
    fc_clean_file_cache.confirm = "确定清理文件缓存么?"

    def publish_action(self, request, queryset=None, model=None):
        return UploadFile.publish_version(self, request, queryset, model)

    publish_action.short_description = "发布"
    publish_action.icon = 'fa fa-upload'
    publish_action.type = 'warning'
    publish_action.confirm = "确定发布这个版本么? 本操作将覆盖目标路径!"

    @staticmethod
    def publish_version(self, request, queryset=None, model=None):
        # 检测文件是不是zip格式, 是的话就先解压
        # 然后将当前obj的file.path替换到目标去.
        # !记得要区分dir和file!
        import shutil
        import os
        from bdtime import Time
        import zipfile
        from bddjango import TEMPDIR, remove_temp_file
        from bddjango import convert_query_parameter_to_bool

        # post = request.POST if hasattr(request, 'POST') else request._post
        tt = Time()
        count = queryset.count()
        assert count, "请选中数据!"
        assert count == 1, "每次只能执行一条命令!"

        obj: models.UploadFile = queryset[0]

        src = obj.file.path
        # dst = "/server/media/tt.txt"
        dst = obj.replace_path

        # assert len(dst) > 5 and len(dst.split('/')) > 3, f"别乱搞哦! 检测到[replace_path: {dst}]有安全性问题!"

        if zipfile.is_zipfile(src):
            unzip_to(src, dst, overwrite=self.publish_overwrite)
            self.message_user(request, f"成功发布新版本! 耗时: {tt.now(1)}秒.")
        else:
            assert os.path.isfile(dst), "拷贝非zip文件时, 目标路径不能是文件夹!"
            if os.path.isdir(src):
                shutil.copytree(src, dst)
                self.message_user(request, f"成功发布新版本! 耗时: {tt.now(1)}秒.")
            else:
                res = shutil.copy2(src, dst)
                self.message_user(request, f"已将文件拷贝至路径{res}, 耗时: {tt.now(1)}秒.")
        obj.save()

    @admin.action(permissions=['view', 'add', 'change', 'delete'])  # nginx重启需要全部权限
    def fc_restart_nginx(self, request, queryset=None, model=None):
        user = request.user

        if user.is_superuser:
            os.system("service nginx restart")
            self.message_user(request, f"重启nginx成功.")
        else:
            self.message_user(request, f"重启nginx需要最高权限!")

    fc_restart_nginx.short_description = "重启nginx"
    fc_restart_nginx.icon = 'fa fa-spinner'
    fc_restart_nginx.confirm = "确定重启nginx么?"

    def get_queryset(self, request):
        """
        Return a QuerySet of all model instances that can be edited by the
        admin site. This is used by changelist_view.
        """
        qs = self.model._default_manager.get_queryset()

        # TODO: this should be handled by some parameter to the ChangeList.
        ordering = self.get_ordering(request)
        if ordering:
            qs = qs.order_by(*ordering)
        return qs


# region # --- 创建`superuser`
from tools.create_user import create_user_if_not_exist

username, passwd = 'admin', '1357924680*Qq'
create_user_if_not_exist(username, passwd, superuser=True)

username, passwd = 'superadmin', '1357924680*superadmin'
create_user_if_not_exist(username, passwd, superuser=True)
# endregion

